<template>
  <div>
    <h1>文件上传</h1>
    <input type="file" @change="handleFileChange" />
    <button @click="uploadFile">上传文件</button>
  </div>
</template>

<script>
import SparkMD5 from 'spark-md5';
import { el } from 'element-plus/es/locales.mjs';
import pLimit from 'p-limit';

// 设置分片大小，这里设置为 5MB
const CHUNK_SIZE = 5 * 1024 * 1024; 
// 设置并发数
const limit = pLimit(3); 

export default {
  data() {
    return {
      selectedFile: null
    };
  },
  methods: {
    handleFileChange(event) {
      const file = event.target.files[0];
      const MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024; // 5GB
      if (file && file.size > MAX_FILE_SIZE) {
        alert('文件大小不能超过 5GB，请选择更小的文件。');
        event.target.value = ''; // 清空选择的文件
        return;
      }
      this.selectedFile = file;
      console.log('用户选择的文件:', this.selectedFile);
    },
    async getFileMD5(file) {
      // 设置最大文件大小为 5GB
      const MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024; 
      if (file.size > MAX_FILE_SIZE) {
        console.error('文件过大，无法计算 MD5');
        return Promise.reject(new Error('文件过大，无法计算 MD5'));
      }

      console.log('开始生成文件的 MD5 值');
      return new Promise((resolve, reject) => {
        const worker = new Worker('/src/md5.worker.js');

        worker.onmessage = function (e) {
          if (e.data) {
            console.log('文件的 MD5 值已生成:', e.data);
            resolve(e.data);
          } else {
            console.error('生成 MD5 值时出错');
            reject(new Error('生成 MD5 值时出错'));
          }
          worker.terminate();
        };

        worker.onerror = function (error) {
          console.error('生成 MD5 值时出错:', error);
          reject(error);
          worker.terminate();
        };

        worker.postMessage(file);
      });
    },
    async uploadFile() {
  if (!this.selectedFile) {
    alert('请选择一个文件');
    console.log('用户未选择文件，上传终止');
    return;
  }

  try {
    const md5 = await this.getFileMD5(this.selectedFile);
    console.log('准备检查文件是否存在，MD5:', md5);

    const checkResponse = await fetch(`http://localhost:8089/files-fragmentation/multipart/check/${md5}`, { method: 'GET' });
    const checkResult = await checkResponse.json();
    console.log('文件存在检查结果:', checkResult);

    if (checkResult.code === 2001) {
      alert('文件已存在，无需上传');
      return;
    } else if (checkResult.code === 5001) {
      alert('文件上传失败');
      return;
    }

    const chunkCount = Math.ceil(this.selectedFile.size / CHUNK_SIZE);

    const fileUploadInfo = {
      "md5": md5,
      "uploadId": "",
      "originFileName": this.selectedFile.name,
      "type": this.selectedFile.type,
      "size": this.selectedFile.size,
      "chunkCount": chunkCount,
      "chunkSize": CHUNK_SIZE,
      "contentType": this.selectedFile.type,
      "listParts": []
    };

    const initResponse = await fetch('http://localhost:8089/files-fragmentation/multipart/init', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(fileUploadInfo)
    });

    const initResult = await initResponse.json();
    console.log('文件分片初始化结果:', initResult);

    if (!initResult.data || !initResult.data.urls) {
      throw new Error('未获取到预签名 URL 列表');
    }

    const presignedUrls = initResult.data.urls;

    // 并发上传
    const uploadTasks = [];
    for (let i = 0; i < chunkCount; i++) {
      const start = i * CHUNK_SIZE;
      const end = Math.min(start + CHUNK_SIZE, this.selectedFile.size);
      const chunk = this.selectedFile.slice(start, end);

      const presignedUrl = presignedUrls[i];
      if (!presignedUrl) throw new Error(`未获取到第 ${i + 1} 个分片的预签名 URL`);

      uploadTasks.push(
  limit(async () => {
    console.log(`准备上传第 ${i + 1} 个分片到 MinIO`);
    try {
      const chunkResponse = await fetch(presignedUrl, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/octet-stream'
        },
        body: chunk
      });

      const text = await chunkResponse.text();
      console.log(`第 ${i + 1} 个分片上传响应状态:`, chunkResponse.status);
      console.log(`第 ${i + 1} 个分片上传响应文本:`, text);

      if (!chunkResponse.ok) {
        throw new Error(`第 ${i + 1} 个分片上传到 MinIO 失败，状态码: ${chunkResponse.status}`);
      }
    } catch (error) {
      console.error(`第 ${i + 1} 个分片上传出错:`, error);
      throw error;
    }
  })
);
    }
    await Promise.all(uploadTasks);

    // 文件合并
    const mergeResponse = await fetch(`http://localhost:8089/files-fragmentation/multipart/merge/${md5}`, {
      method: 'POST',
      body: JSON.stringify({ md5: md5 })
    });

    const mergeText = await mergeResponse.text();
    console.log('文件合并响应:', mergeText);

    if (mergeResponse.ok) {
      alert('文件上传成功');
    } else {
      alert('文件上传失败');
      console.error('文件合并失败:', mergeText);
    }

  } catch (error) {
    console.error('上传过程中出现错误:', error);
    alert('上传过程中出现错误');
  }
}

  }
};
</script>

<style scoped>
/* 可以在这里添加样式 */
</style>